package com.hifar.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.hifar.utils.ToolKit;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zhuWeiWei
 * @description TODO
 * @date 2025/6/16 14:54
 */
@MappedTypes(Map.class)
public class AdvancedMapTypeHandler extends BaseTypeHandler<Map<String, Object>> {

    private final ObjectMapper objectMapper = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
                                    Map<String, Object> parameter,
                                    JdbcType jdbcType) throws SQLException {
        try {
            Map<String, Object> processed = processMap(parameter);
            ps.setString(i, objectMapper.writeValueAsString(processed));
        } catch (JsonProcessingException e) {
            throw new SQLException("Failed to serialize map to JSON", e);
        }
    }

    @Override
    public Map<String, Object> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return null;
    }

    @Override
    public Map<String, Object> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public Map<String, Object> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }

    private Map<String, Object> processMap(Map<String, Object> original) {
        Map<String, Object> result = new LinkedHashMap<>();
        original.forEach((key, value) -> {
            String columnName = ToolKit.camelToSnake(key);
            Object convertedValue = convertValue(value);
            result.put(columnName, convertedValue);
        });
        return result;
    }

    private Object convertValue(Object value) {
        if (value == null) {
            return null;
        }

        // 处理日期时间类型
        if (value instanceof TemporalAccessor) {
            if (value instanceof LocalDate) {
                return ((LocalDate) value).format(DateTimeFormatter.ISO_LOCAL_DATE);
            } else if (value instanceof LocalDateTime) {
                return ((LocalDateTime) value).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            } else if (value instanceof Instant) {
                return ((Instant) value).atZone(ZoneId.systemDefault()).toLocalDateTime()
                        .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            }
        }

        // 处理枚举类型
        if (value instanceof Enum) {
            return ((Enum<?>) value).name();
        }

        return value;
    }
}
